'use strict'

/**
 * <--    还原前    -->
var a = 123;
const b = -5;
let c = window;
function d()
{
    var f = c.btoa("hello,AST!");
    return a + b + f ;
}
 * 
 * <--    特点    -->
 * 单看这段代码是没有可值得还原的地方，但是假若声明的变量（绑定）在初始化后，都是直接被引用，没有被修改过
 * 那么直接将a,b,c替换为初始化值，就更利于阅读
 * 
 * <--    解决办法    -->
 * 在 VariableDeclarator.enter 时，获取到该 binding，进而获取到所有引用的 refPath ，进而节点替换；删除垃圾变量定义
 * 
 * <--    冗余判断    -->
 * 1. 声明的变量初始化时数据类型要么是字面量（负数为UnaryExpression），要么是引用的一个变量
 * 2. 该变量在作用域中没有被修改过
 * 
 * <--    还原后    -->
function d() {
  var f = window.btoa("hello,AST!");
  return 123 + -5 + f;
}
 **/

const {parse} = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const t = require('@babel/types');
const generator = require('@babel/generator').default;

let code = `
var a = 123;
const b = -5;
let c = window;
function d()
{
  var f = c.btoa("hello,AST!");
  return a + b + f ;
}`

let ast = parse(code);

let visitor = {
    VariableDeclarator:{
        enter: function(path){
            let name = path.node.id.name, initPath = path.get('init');
            let binding = path.scope.getBinding(name);
            if(!binding || !binding.constant){return}

            if(t.isUnaryExpression(initPath.node)){
                let {confident} = initPath.evaluate();
                // console.log(confident, value);
                if(!confident){
                    return
                }
            }else if(!t.isLiteral(initPath.node) && !t.isIdentifier(initPath.node)){
                return
            }

            for(let refPath of binding.referencePaths){
                // console.log(refPath.toString());
                refPath.replaceInline(initPath.node);
            }

            path.remove();
        },
    },
}

traverse(ast, visitor);
let answer = generator(ast).code

console.log(answer);
